//
// Created by 23216 on 24-11-19.
//

#ifndef ASTDECLARATION_H
#define ASTDECLARATION_H

#include <utility>
#include <vector>
#include <map>
#include <optional>
#include <variant>

#include "ASTStatement.h"

namespace ast {
    using std::vector;
    using std::map;
    using std::optional;


    struct DeclarationTypedef final : Declaration {
        string type;

        DeclarationTypedef(string name, string type) : Declaration(Typedef, std::move(name), true),
                                                       type(std::move(type)) {
        }

        static bool classof(const ASTBase *base) {
            return base->getKind() == Typedef;
        }
    };

    struct DeclarationBuiltinType final : Declaration {
        type::ASTType type;
        vector<ast::Expression *> dimensions;
        struct Expression *initializer;

        DeclarationBuiltinType(string name, type::ASTType type,
                               const vector<ast::Expression *> &dimensions, struct Expression *initializer,
                               bool isConst)
            : Declaration(BuiltinType, std::move(name), isConst),
              type(type), dimensions(dimensions), initializer(initializer) {
        }

        static bool classof(const ASTBase *base) {
            return base->getKind() == BuiltinType;
        }
    };

    struct DeclarationFunction final : Declaration {
        // todo: function attributes

        vector<DeclarationBuiltinType *> params;
        type::ASTType return_type;

        StatementCompound *content;

        DeclarationFunction(string name, const type::ASTType &return_type,
                            const vector<DeclarationBuiltinType *> &params,
                            StatementCompound *content) : Declaration(Function, std::move(name), true), params(params),
                                                          return_type(return_type), content(content) {
        }

        static bool classof(const ASTBase *base) {
            return base->getKind() == Function;
        }
    };


    // // struct union enum
    // struct DeclarationUserDefinedType : Declaration {
    //     DeclarationUserDefinedType(ASTKind kind, string name) : Declaration(kind, std::move(name)) {
    //     }
    //
    //     static bool classof(ASTBase *base) {
    //         return base->getKind() < UserDefinedTypeEnd && base->getKind() >= UserDefinedType;
    //     }
    // };
    //
    // struct DeclarationUserDefinedTypeStruct final : DeclarationUserDefinedType {
    //     // name, type
    //     map<string, string> fields;
    //
    //     DeclarationUserDefinedTypeStruct(string name, map<string, string> fields) : DeclarationUserDefinedType(
    //             UserDefinedTypeStruct, std::move(name)), fields(std::move(fields)) {
    //     }
    //
    //     static bool classof(ASTBase *base) {
    //         return base->getKind() == UserDefinedTypeStruct;
    //     }
    // };
    //
    // struct DeclarationUserDefinedTypeUnion final : DeclarationUserDefinedType {
    //     // name, type
    //     map<string, string> fields;
    //
    //     DeclarationUserDefinedTypeUnion(string name, map<string, string> fields) : DeclarationUserDefinedType(
    //             UserDefinedTypeUnion, std::move(name)), fields(std::move(fields)) {
    //     }
    //
    //     static bool classof(const ASTBase *base) {
    //         return base->getKind() == UserDefinedTypeUnion;
    //     }
    // };
    //
    // struct DeclarationUserDefinedTypeEnum final : DeclarationUserDefinedType {
    //     map<string, int> fields;
    //
    //     DeclarationUserDefinedTypeEnum(string name, map<string, int> fields) : DeclarationUserDefinedType(
    //                                                                                UserDefinedTypeEnum,
    //                                                                                std::move(name)),
    //                                                                            fields(std::move(fields)) {
    //     }
    //
    //     static bool classof(const ASTBase *base) {
    //         return base->getKind() == UserDefinedTypeEnum;
    //     }
    // };

    // // todo: support for struct, union and enums
    // struct DeclarationValue final : Declaration {
    //     ASTBase *type;
    //
    //     DeclarationValue(string name, ASTBase *type) : Declaration(Value, std::move(name)), type(type) {
    //     }
    //
    //     static bool classof(const ASTBase *base) {
    //         return base->getKind() == Value;
    //     }
    // };
};

#endif //ASTDECLARATION_H
